﻿using System;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;

namespace ICodeShare.UI.Converters
{
    #region IValueConverter
    /// <summary>
    /// 二值化反颜色转换器
    /// </summary>
    /// <example>
    /// 1.在xmal文件引用DateConverter类所在命名空间。
    ///   xmlns:cvts="http://schemas.extended.wpf.com/converters"
    /// 2.在xaml文件添加Resources。
    ///   <Window.Resources>
    ///   <cvts:BackgroundToForegroundConverter x:Key="cvtsBackgroundToForeground"/>
    ///   </Window.Resources>
    /// 3.在xaml文件中指定Binding值的Converter
    ///     <ContentControl.Foreground>
    ///          <MultiBinding Converter="{x:Static Converters:BackgroundToForegroundConverter.Instance}">
    ///               <Binding ElementName="PART_WindowTitleBackground"
    ///                       Path="Fill"
    ///                      Mode="OneWay" />
    ///             <Binding RelativeSource="{RelativeSource TemplatedParent}"
    ///                       Path="TitleForeground"
    ///                      Mode="OneWay" />
    ///         </MultiBinding>
    ///     </ContentControl.Foreground>
    /// </example>
    /// <remarks>
    /// 参数parameter应该包含该一个参数或两个以分号(;)分隔的参数.
    /// 如果参数parameter包含两个字符串，第一个字符串表示条件为假的值，第二个字符串表示条件为真的值。.
    /// 如果参数parameter包含一个字符串，这个字符串则表示条件为真的值，条件为假的值用空字符串表示.
    /// 如果参数parameter未声明，则用1表示条件为真的值，用0表示条件为假的值.
    /// </remarks>
    public sealed class InverseColorToBinaryConverter : IValueConverter, IMultiValueConverter
    {
        #region  Members 成员变量
        private static InverseColorToBinaryConverter _instance;
        #endregion

        #region Constructors 构造函数
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static InverseColorToBinaryConverter()
        {
        }

        private InverseColorToBinaryConverter()
        {
        }
        #endregion

        #region  Properties 属性
        public static InverseColorToBinaryConverter Instance
        {
            get { return _instance ?? (_instance = new InverseColorToBinaryConverter()); }
        }
        #endregion

        #region  Base Class Overrides 基类方法重写

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is SolidColorBrush)
            {
                var idealForegroundColor = this.IdealTextColor(((SolidColorBrush)value).Color);
                var foreGroundBrush = new SolidColorBrush(idealForegroundColor);
                foreGroundBrush.Freeze();
                return foreGroundBrush;
            }
            return Brushes.White;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return DependencyProperty.UnsetValue;
        }

        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            var bgBrush = values.Length > 0 ? values[0] as Brush : null;
            var titleBrush = values.Length > 1 ? values[1] as Brush : null;
            if (titleBrush != null)
            {
                return titleBrush;
            }
            return Convert(bgBrush, targetType, parameter, culture);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            return targetTypes.Select(t => DependencyProperty.UnsetValue).ToArray();
        }
        #endregion

        #region Methods 方法
        /// <summary>
        /// Determining Ideal Text Color Based on Specified Background Color
        /// http://www.codeproject.com/KB/GDI-plus/IdealTextColor.aspx
        /// </summary>
        /// <param name = "bg">The bg.</param>
        /// <returns></returns>
        private Color IdealTextColor(Color bg)
        {
            const int nThreshold = 105;
            var bgDelta = System.Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + (bg.B * 0.114));
            var foreColor = (255 - bgDelta < nThreshold) ? Colors.Black : Colors.White;
            return foreColor;
        }
        #endregion
    }
    #endregion
}
